package com.elnguage.lox;

import com.elnguage.lox.Expr.Assign;
import com.elnguage.lox.Expr.Binary;
import com.elnguage.lox.Expr.Call;
import com.elnguage.lox.Expr.EventCat;
import com.elnguage.lox.Expr.Grouping;
import com.elnguage.lox.Expr.Literal;
import com.elnguage.lox.Expr.Logical;
import com.elnguage.lox.Expr.Variable;

public class AstPrinter implements Expr.Visitor<String>{
    String print(Expr expr)
    {
        return expr.accept(this);
    }



    @Override
    public String visitBinaryExpr(Expr.Binary expr)
    {
        return parenthesize(expr.operator.lexeme, expr.left, expr.right);
    }

    @Override
    public String visitGroupingExpr(Expr.Grouping expr)
    {
        return parenthesize("group", expr.expression);
    }

    @Override
    public String visitLiteralExpr(Expr.Literal expr)
    {
        if(expr.value == null) return "nil";
        return expr.value.toString();
    }

    @Override
    public String visitUnaryExpr(Expr.Unary expr)
    {
        return parenthesize(expr.operator.lexeme, expr.right);
    }

    private String parenthesize(String terminate, Expr... exprs)
    {
        StringBuilder builder = new StringBuilder();

        builder.append("(").append(terminate);
        for (Expr expr : exprs)
        {
            builder.append(" ");
            builder.append(expr.accept(this));
        }
        builder.append(")");
        return builder.toString();
    }



    @Override
    public String visitAssignExpr(Assign expr) {
        StringBuilder builder = new StringBuilder();
        builder.append("(").append(expr.name).append(expr.accept(this)).append(")");
        return builder.toString();
    }



    @Override
    public String visitCallExpr(Call expr) {
        return String.format("(Call %s)", expr.callee.accept(this));
    }



    @Override
    public String visitLogicalExpr(Logical expr) {
        return parenthesize(expr.operator.lexeme, expr.left, expr.right);
    }



    @Override
    public String visitVariableExpr(Variable expr) {
        return expr.name.lexeme;
    }



    @Override
    public String visitEventCatExpr(EventCat expr) {
        return parenthesize("->", expr.prev, expr.cosq);
    }

    // public static void main(String[] args)
    // {
    //     Expr test = new Expr.Binary(new Literal("abc"), new Token(TokenType.AND, "and", null, 1), new Literal("123"));
    //     //Expr expression = new Expr.Binary(new Expr.Unary(new Token(TokenType.MINUS, "-", null, 1), new Expr.Literal("123")), new Token(TokenType.STAR, "*", null, 1), new Expr.Grouping(new Expr.Literal(123.333)));
    //     //System.out.println(new AstPrinter().print(expression));
    //     System.out.println(test.accept(new AstPrinter()));
    // }

}
